#include <iostream>
#include <string>
#include <thread>
#include <chrono>
#include <mutex>

#include "DemoMultiThread.h"
#include "DemoDateTime.h"

using namespace std;

mutex g_mutexA;
mutex g_mutexB;

void taskA(int runTimeInMS) {
    logWs("taskA begin");
    
    srand((int)(getTsInWeimiao()));     // 每次执行种子不同，生成不同的随机数
    int sleepMS = rand() % 2000;     // 2s 内的随机数
    cout<<"taskA, tid="<<this_thread::get_id()<<", sleepMS="<<sleepMS<<endl;
    this_thread::sleep_for(std::chrono::milliseconds(sleepMS));
    g_mutexA.unlock();
    logWs("taskA end");
}

void taskB(int& runTimeInMS) {
    logWs("taskB begin");
    cout<<"taskB, tid="<<this_thread::get_id()<<"runTimeInMS="<<runTimeInMS<<endl;
    runTimeInMS+=100;
    this_thread::sleep_for(std::chrono::milliseconds(runTimeInMS));
    g_mutexB.unlock();
    logWs("taskB end");
}

void taskC(int runTimeInMS) {
    logWs("taskC begin");
    g_mutexA.lock();
    g_mutexB.lock();
    logWs("taskC get lock");
    
    srand((int)(getTsInWeimiao()));     // 每次执行种子不同，生成不同的随机数
    int sleepMS = rand() % 2000;     // 2s 内的随机数
    cout<<"taskC, tid="<<this_thread::get_id()<<", sleepMS="<<sleepMS<<endl;
    this_thread::sleep_for(std::chrono::milliseconds(sleepMS));
    logWs("taskC end");
}

void taskD(int runTimeInMS) {
    logWs("taskD begin");
    
    srand((int)(getTsInWeimiao()));     // 每次执行种子不同，生成不同的随机数
    int sleepMS = rand() % 2000;     // 2s 内的随机数
    cout<<"taskD, tid="<<this_thread::get_id()<<", sleepMS="<<sleepMS<<endl;
    this_thread::sleep_for(std::chrono::milliseconds(sleepMS));
    logWs("taskD end");
}

void DemoMultiThread(void) {
    cout<<endl<<endl<<"DemoMultiThread"<<endl;
    logWsBegin("DemoMultiThread begin");
    
    // 4个任务ABCD
    // C依赖AB完成
    // D和ABC无关，期望尽量快执行完成所有任务
    
    g_mutexA.lock();
    std::thread tA(taskA, 500); // pass by value
    
    int runtime = 600;
    g_mutexB.lock();
    std::thread tB(taskB, ref(runtime)); // pass by reference
    
    std::thread tC(taskC, 650);
    
    std::thread tD(taskD, 450);
    
    tA.join();
    tB.join();
    tC.join();
    tD.join();
    logWs("after tB.join(), runtime=%d", runtime);
    logWs("DemoMultiThread end");
}
